<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../js/vue.js"></script>
    <style>
        .comp-a,
        .comp-b,
        .comp-c {
            line-height: 40px;
            padding: 10px;
            margin: 10px auto;
            border: 1px dashed #333;
        }
    </style>
</head>

<body>
    <!-- 根组件 -->
    <div id="app">
        <p>a:{{a}}</p>
        <p><button @click="a++">a++</button></p>
        <p>b:{{b}}</p>
        <p><button @click="b++">b++</button></p>
      
        <laowang-a ></laowang-a>
    </div>
</body>
<script>
    /*  
        provide和inject 依赖注入
            以允许一个祖先组件向其所有子孙后代注入一个依赖，不论组件层次有多深，并在其上下游关系成立的时间里始终生效

        provide 选项应该是一个对象或返回一个对象的函数, 一般用在父(代)组件,向子(代)组件注入依赖数据/方法


        inject  子组件对应属性名接收数据
            inject 选项应该是一个数组或一个对象
            1. inject选项是一个数组, 子组件对应属性名接收父组件传入的数据 (属性名保持一直)
                子组件["a"] = 父组件注入数据["a"]
            2. inject选项是一个对象,  子组件对应属性名接收父组件传入的数据 (子组件可以自定义属性名)
                子组件["A"] = 父组件注入数据["a"]

    
    */


    // (1) 通过对象将组件的配置存储起来



    let LaowangC = {
        // inject选项是一个对象 
        // 对象的键名: 当前组件接收数据的属性名
        // 对象的键值: 父代组件传入数据的属性名
        // 子组件["A"] = 父组件注入数据["a"]
        
        inject:["getA","getB","setA","setB"],
        template: `<div class="comp-c">
                    这是C组件: {{getA()}}----{{getB()}}
                    <p>
                        <button @click="setA(getA()+1)">a++</button>
                        <button @click="setB(getB()+1)">a++</button>
                        </p>
                </div>`,
        mounted(){
            console.log("组件C",this);
        }
    }

    let LaowangB = {
        // 如果子组件 inject接收的数据 和 自身组件定义的数据(data)重名  => 则使用自己的
        inject:["a","b"],
        template: `<div class="comp-b">
                    这是B组件: {{a}} --- {{b}}  
                    <laowang-c ></laowang-c>
                </div>`,
        components:{
            LaowangC 
        },
    }

  
    let LaowangA = {
        // inject选项是一个数组, 子组件对应属性名接收父组件传入的数据
        // 子组件["a"] = 父组件注入数据["a"]
        template: `<div class="comp-a">
                    这是A组件:
                    <laowang-b></laowang-b>
                </div>`,
        components:{
            LaowangB 
        },
       
    }


    // 根组件 => 挂载到页面最外层中 (所有组件,都是根组件的子组件)

    

    var vm = new Vue({
        el: "#app",
        data: {
            a: 1,
            b: 2,
        },
        methods:{
            update:function(val){ // this => vm
                this.count = val;
            }
        },
        components:{
            // components 局部组件注册 (使用时才会被注册)
            // 对象的键名: 就是局部组件的组件名
            // 对象的键值: 局部组件的配置项 
            "laowang-a": LaowangA
        },

        // 父组件注入依赖数据 !!
        //  provide 选项是一个对象 (注意: 注入的依赖数据只能是定死的值, 无法使用当前Vue实例挂载的数据和方法)
        // provide:{
        //     a: 1,
        //     b: 2,
        // }

        // provide 选项也可以是一个返回对象的函数
        provide:function(){
            console.log("125 this",this);  // this -> vm

            return {
                a: this.a,  //  a:1   this.a => 取值操作, 先取值,将值放到对象中,再将对象作为依赖数据注入
                b: this.b,  //  b:2

                // provide中函数的this没有强制指向当前vue实例  => 哪个实例调用就指向谁
                // getA:function(){  
                //     console.log("135 this",this);
                //     return this.a;
                // },
                // getB:function(){
                //     console.log("139 this",this);
                //     return this.b;
                // }

                getA:()=>{  
                    console.log("135 this",this);
                    return this.a;
                },
                setA:(val)=>{
                    this.a = val;
                },
                getB:()=>{
                    console.log("139 this",this);
                    return this.b;
                },
                setB:(val)=>{
                    this.b = val;
                },

            }
        }

    })



</script>

</html>